package javaLearning.泛型;

import java.util.ArrayList;
import java.util.List;

/**
 * 泛型类
 * @author : K k
 * @date : 17:35 2020/9/13
 */
public class GenericDemo<T> extends AbstractGenericDemo<T> {

    @Override
    public void action1(T o) {
        System.out.println(o.getClass());
    }

    public static void main(String[] args) {
        GenericDemo<Integer> objectDemo2 = new GenericDemo<>();
        objectDemo2.action1(1);


        /**
         * 这种情况下，由于JVM泛型的擦除机制，在运行时JVM是不知道泛型信息的，
         * 所以可以给oa[1]赋上一个ArrayList而不会出现异常，但是在取出数据的时候却要做一次类型转换，
         * 所以就会出现ClassCastException，如果可以进行泛型数组的声明，
         * 上面说的这种情况在编译期将不会出现任何的警告和错误，只有在运行时才会出错。
         * 而对泛型数组的声明进行限制，对于这样的情况，可以在编译期提示代码有类型安全问题，比没有任何提示要强很多。
         */
//        List<String>[] lsa = new List<String>[10]; // Not really allowed.
//        Object o = lsa;
//        Object[] oa = (Object[]) o;
//        List<Integer> li = new ArrayList<Integer>();
//        li.add(new Integer(3));
//        oa[1] = li; // Unsound, but passes run time store check
//        String s = lsa[1].get(0); // Run-time error: ClassCastException.

        //下面采用通配符的方式是被允许的:数组的类型不可以是类型变量，
        // 除非是采用通配符的方式，因为对于通配符的方式，最后取出数据是要做显式的类型转换的。
        List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.
        Object o = lsa;
        Object[] oa = (Object[]) o;
        List<Integer> li = new ArrayList<Integer>();
        li.add(new Integer(3));
        oa[1] = li; // Correct.
        Integer i = (Integer) lsa[1].get(0); // OK
    }

    //在使用泛型的时候，我们还可以为传入的泛型类型实参进行上下边界的限制，
    // 如：类型实参只准传入某种类型的父类或某种类型的子类。
    public void showKeyValue1(GenericMethodDemo.Generic<? extends Number> obj){
        System.out.println("泛型测试 "+"key value is " + obj.getKey());
    }

    //在泛型方法中添加上下边界限制的时候，必须在权限声明与返回值之间的<T>上添加上下边界，即在泛型声明的时候添加
    //public <T> T showKeyName(Generic<T extends Number> container)，编译器会报错："Unexpected bound"
    public <T extends Number> T showKeyName(GenericMethodDemo.Generic<T> container){
        System.out.println("container key :" + container.getKey());
        T test = container.getKey();
        return test;
    }
}
